﻿using System;
using System.Collections.Generic;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sern.Abstracts.Booster;
using Sern.Abstracts.Common;
using Sern.Abstracts.Splitter;
using Sern.Abstracts.Tracker.DataContracts;
using Sern.Abstracts.Tracker.ServiceContracts;
using Sern.Abstracts.Tracker.ServiceContracts.Fakes;
using Sern.Common;
using Sern.Common.Fakes;
using Sern.ServiceImplementation;
using Sern.ServiceImplementation.Fakes;
using Sern.ServiceImplementation.MapReduce;
using Microsoft.Practices.Unity;
using LocalRegistrar = Sern.ServiceImplementation.MapReduce.LocalRegistrar;

namespace Sern.Test.ServiceImplementation.MapReduce
{
    [TestClass]
    public class MapReduceClientAbstract_OrderOfNotification
    {
        List<ProcessingNotice> notices = new List<ProcessingNotice>();


        [TestInitialize]
        public void TestInitialize()
        {
            var jobId = Guid.NewGuid();

            ComponentLocator.Reset();

            bool[] isSatisfied = new[] {false, true};
            int isSatisfiedIndex = 0;

            var mapReduce = new MapReduce<object, object>
                (
                    () => new StubIClient<ITrackerTelemetryReceiver>
                    {
                        ProxyGet = () => new StubITrackerTelemetryReceiver
                            {
                                NotifyProcessingNotice = notice => notices.Add(notice),
                            }
                    },
                //TODO: Next one test if tracing is done correctly, then test if error logging is also done correctly.
                    () => new StubIClient<ITrackerLogging>
                        {
                            ProxyGet = () => new StubITrackerLogging
                                {
                                    LogEmissionTrace = trace => { },
                                }
                        },
                       (guid0, guid) => isSatisfied[isSatisfiedIndex++],
                       Guid.NewGuid(),
                       Guid.NewGuid(),
                       (key,value) => {/*Does not invoke next service*/ },
                       (key, value, action) => action("newKey","newValue")
                );

            ComponentLocator.Unity.RegisterInstance<IMapReduce<object, object>>(mapReduce);            
        }

        [TestMethod]
        public void TestNoticesAreFiredInOrder()
        {
            var mapReduceObject = ComponentLocator.Unity.Resolve<IMapReduce<object, object>>();
            mapReduceObject.Handle("startKey", "startValue");

            //TODO: Change the thread sleep to a reset event.
            Thread.Sleep(50);

            Assert.AreEqual(notices[0].Key,  "startKey".GetKeyHash());
            Assert.AreEqual(notices[0].ProcessingStage, ProcessingStage.Processing);
            Assert.AreEqual(notices[0].ParentKey, Guid.Empty);

            //New key gets initiated before the old key can be ended, this way the tracker can tell if there's a hanging key still processing.
            Assert.AreEqual(notices[1].Key, "newKey".GetKeyHash());
            Assert.AreEqual(notices[1].ProcessingStage, ProcessingStage.Initiated);
            Assert.AreEqual(notices[1].ParentKey, "startKey".GetKeyHash());

            //Now the start key is ended.
            Assert.AreEqual(notices[2].Key, "startKey".GetKeyHash());
            Assert.AreEqual(notices[2].ProcessingStage, ProcessingStage.Completed);
            Assert.AreEqual(notices[2].ParentKey, Guid.Empty);
        }
    }
}
